#include "MultiCouleurs.hpp"

#include "Melange.hpp"

using namespace std;
using namespace boost::assign;

/**
 * Constructeur standard, qui initialise les champs de la classe
 * mère. Cette version ne permet pas d'introduire une perturbation de
 * la normale.
 *
 * La version par défaut crée des niveaux de gris (entre blanc et
 * noir).
 *
 * @param refl coefficient de réflexion.
 * @param trans coefficient de transparence.
 * @param indice indice de réfraction.
 * @param reg coefficient de diffusion.
 * @param couleurs conteneur des instances de Couleur à utiliser.
 * @param mel conteneur des seuils à utiliser pour les mélanges de             
 * couleurs.
 * @param coeff intensité de la perturbation.
 */
MultiCouleurs::MultiCouleurs(const double& refl, const double& trans,
			     const double& indice, const double& reg, 
			     const vector< Couleur >& couleurs,
			     const vector< double >& mel,
			     const double& coeff)
  : EffetBase( refl, trans, indice, reg, couleurs, mel, coeff ),
    Generateur( 10, .5, 1 )
{
  unsigned int taille( min( couleurs.size(), mel.size() ) );

  Colors.resize( taille );
  Melange.resize( taille );

  Type = tMultiCouleurs;
}

/**
 * Constructeur standard, qui initialise les champs de la classe
 * mère. Cette version permet d'introduire une perturbation de la
 * normale.
 *
 * @param refl coefficient de réflexion.
 * @param trans coefficient de transparence.
 * @param indice indice de réfraction.
 * @param reg coefficient de diffusion.
 * @param bruit perturbation sur la normale.
 * @param couleurs conteneur des instances de Couleur à utiliser.
 * @param mel conteneur des seuils à utiliser pour les mélanges de             
 * couleurs.
 * @param coeff intensité de la perturbation.
 */
MultiCouleurs::MultiCouleurs(const double& refl, const double& trans,
			     const double& indice, const double& reg, 
			     const double& bruit, 
			     const vector< Couleur >& couleurs,
			     const vector< double >& mel,
			     const double& coeff)
  : EffetBase( refl, trans, indice, reg, bruit, couleurs, mel,
	       coeff ), Generateur( 10, .5, 2 )
{
  unsigned int taille( min( couleurs.size(), mel.size() ) );

  Colors.resize( taille );
  Melange.resize( taille );

  Type = tMultiCouleurs;
}

/**
 * Le destructeur n'a rien de spécial à faire.
 */
MultiCouleurs::~MultiCouleurs()
{}

/**
 * Permet de récupérer la couleur du point voulu.
 *
 * On commence par déterminer la valeur du bruit associée au point,
 * puis on détermine quelles sont les deux couleurs que l'on va devoir
 * mélanger. Le mélange est ensuite effectué.
 *
 * @param pt point de la surface que l'on veut colorier.
 * @return une référence constante sur Color, que l'on modifie ici.
 */
Couleur MultiCouleurs::couleur(const Coord& pt)
{
  double val( valeurBruit( pt ) );

  vector< Couleur > col;
  vector< double > poids;

  unsigned int i;

  for (i = 0; i < 3; i++)
    {
      if ( val > Melange[ i ] )
	break;
    }

  col = list_of( Colors[ i ] )( Colors[ i + 1 ] );
  poids =                                                                     
    list_of( ( val - Melange[ i ] ) / ( Melange[ i + 1 ] - Melange[ i ] ) )     
    ( ( Melange[ i + 1 ] - val ) / ( Melange[ i + 1 ] - Melange[ i ] ) );

  return faireMelangeCouleurs( Colors, poids );
}

/**
 * Permet de récupérer la valeur du bruit de Perlin associée au point.*
 *
 * On multiplie tout d'abord le point par Coefficient, afin de régler
 * les problèmes d'échelles.
 *
 * @param pt point de la surface pour lequel on désire la valeur du
 * bruit.
 * @return la valeur du bruit associée à pt.
 */
double MultiCouleurs::valeurBruit(const Coord& pt) const
{
  Coord p( pt );
  p *= Coefficient;
  return Generateur( p.x(), p.y(), p.z() );
}
